home *** CD-ROM | disk | FTP | other *** search
- |
- | The Object Engine
- | C++ Class Library
- | and Code Generator
- | for The Paradox Engine
- |
- | Version 0.9
- |
- | Dr. Mark Brittingham
- |
- |
- |
- |
-
-
- The Object Engine is a C++ class library that encapsulates the core
- functionality of the Paradox Engine database library. This encapsulation
- provides a large degree of OODBMS functionality to engine users. Rather than
- spending your time writing functions to copy data back and forth between
- data structures and record buffers, you need only call "Store", and "Link"
- methods of the object engine's persistant classes. Furthermore, these
- functions (and others) are written for you automatically. You simply
- specify the fields that will populate your new class, and the Code Generator
- automatically generates the class and all of its methods for you! The
- generated code will work under both Windows and DOS and can be compiled
- with Borland C++ 3.1 (a sample is included to help guide you). The library
- covers Alphanumeric, Short, Long, Double, Float (currency), Date and List
- types (see below). Support for Blobs will be added in the version 2.0.
-
- In addition to these features, the object engine provides a unique database
- list class that allows you to store a heterogeneous set of persistant
- objects. You can construct arbitrarily complex data relationships without
- the need for common (relational) fields by placing pointers to these lists
- within persistant classes. You gain nearly all of the power of a
- full fledged OODBMS simply by adding the Object Engine library to your
- current Paradox Engine application. Plus, the library is very efficient:
- it adds less than 13K to your application (with speed optimization).
-
-
- Distribution Policy
- -------------------
- The files contained on this disk: objeng.cpp, objeng.hpp, manual.txt, and
- GEN2.EXE, are all copyrighted material. However, you may use, copy and
- distribute this software free of charge under the following conditions:
-
- 1. Never change any part of the Copyright statement.
-
- 2. All of the enclosed files must be distributed together.
-
- 3. You must not distribute changed versions of the program. I do not
- want to be receiving correspondence about bugs that I have not
- produced. If you have a suggestion, contact me at the address below
- and I will consider your suggestion. If I incorporate your change,
- you will be credited in the documentation.
-
- 4. The author is not liable for any damage on your side caused by
- the use of this program.
-
- 5. The author has no duty to remedy for the deficiencies of the
- program.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- 6. If you wish to distribute this software with publications or
- a product, you must print the BSDI copyright statement somewhere
- on the disk or on the package.
-
- As long as those conditions are satisfied, you do not need to get the
- author's permission to use or to distribute the software.
-
-
- How to contact Brittingham Software Design
- ------------------------------------------
-
- The best way to contact me is to send MAIL to me on CompuServe: 72740,2244.
- If you do not have a CompuServe account, you may write to me at:
-
- Dr. Mark Brittingham
- 15 Pheasant Ct.
- Flanders, NJ 07836
-
-
- Using the Library
- -----------------
- To use the library, you should first plan out your database structure. You
- should have a clear idea of the classes needed in your application and their
- interrelationships. Next, run the Gen2.exe application (it runs under
- Microsoft Windows(tm)) and create each of your classes. Gen2 is quite
- simple. A single button allows you to create a class or to edit whichever
- class is highlighted in a list of classes. You can save your class
- definitions in a format recognized by Gen2 and restore them later. Thus,
- you need not complete the entire set of class definitions in one sitting.
-
- When you are satisfied with the set of classes you have defined, you can
- generate the code to implement these classes as persistant objects with the
- push of a button. You will specify the directory and filename of the header
- and C++ files. Keep in mind that you can go back, change your classes,
- and regenerate your code. However, any changes YOU make to the generated
- code will be overwritten (unless you use another file name). Thus, it is
- probably best to either subclass the generated classes or at least to keep
- your own code separate.
-
- No further documentation is included for the generator simply because it is
- so straightforward. Please fire it up and see for yourself how quickly you
- can generate some real persistant classes.
-
- To work with the generated code, you need to do three things
-
- 1) include the generated header file in the appropriate code files,
- 2) place the generated C++ file in your project or makefile, and
- 3) place the objeng.cpp file in your project/makefile.
-
- Remember what you named the header and C++ files during the generate phase
- so you know what to include in steps 1 and 2. The objeng.cpp file is
- included in the Object Engine Zip file.
-
- Now you are ready to declare, manipulate, store, or retrieve instances of
- the classes you have defined! You never need to worry about initializing the
- engine, manipulating or creating tables, or reading or writing data. Of
- course, you do have control over Paradox Engine initialization as well as
- table manipulation if you need it. But, for the vast majority of your work,
- you need only deal with standard C++ syntax.
-
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- Two Keys To Object Engine Programs
- ----------------------------------
- Two core ideas will help you to understand how to use the library. First, to
- store an object in the library, simply call its "Store" method. To retrieve a
- database record and place it in an object, you will "link" the object to the
- record. This can be done either by the contents of a field (possibly a key
- field), or navigationally (first, next, etc.). Thus "linking" is the act of
- making an in-memory data structure reflect an on-disk record. Of course, you
- needn't think of it in terms of database records at all!
-
- The following link functions are defined:
- LinkToKey (one or more key fields)
- LinkToRecord (a record position)
- LinkToField (contents of a field)
- LinkToID (objectID - see below)
- LinkToFirst
- LinkToLast
- LinkToNext
- LinkToPrev
-
- The second key idea is found in the "objectID". Each object has an objectID
- associated with it. When you link an object to a particular database record,
- your object is given the record's unique objectID. You need to keep this
- in mind when working with persistant classes.
-
- For example, if you create a new object using the copy constructor or set
- one object to another (using '='), then both will have the same objectID.
- If you change these two objects separately and save them both, then the
- record will reflect the last one stored. That is, storage is mediated by
- the objectID. An object without an objectID will be stored as new (assuming
- that there are no conflicting key fields). An object whose objectID
- matches a record found in the database will update that record. If you simply
- keep in mind that an object has an identity that you must respect, you will
- have no problem using the library.
-
- ***************************************************************************
- Persistant Class Functions - Introduction
-
- When you generate code using gen2.exe, you will see that your class
- definition:
-
- a) is derived from "PersistClass",
- b) has one or more variable declarations,
- c) has one or more matching "SetXXX" functions to set the variables,
- d) has one or more "GetXXX" functions to get the value of variables, and
- e) has only six other methods (2 Constructors, operator=, Store, Retrieve,
- and LinkToKey).
-
- If a class contains a list (an "OEList") of other persistant classes, then
- there is no corresponding "GetXXX" function and the "SetXXX" function
- returns a non-const pointer to the actual list. All other returned values
- are const to ensure encapsulation. You can change the "SetXXX" functions to
- reflect any validity checking or dependent variable manipulations that your
- class requires. Since the OEList already features its own encapsulation
- (and since the code generator architecture made it a pain to make the list
- variables public), a non-const pointer to the list is returned from the
- "GetXXX" function.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- In addition to the Set and Get functions and the six defined with the class,
- your class inherits many functions for linking to various records as well
- as functions for testing status, returning Paradox Engine variables (table
- and record handles, etc.), and more.
-
- Functions that return a value will return Paradox Engine error codes
- (PXSUCCESS, PXERR_XXX). In all cases (functions, operators, constructors),
- the variable "status" will be filled with the most recent Paradox operation's
- return value (use GetStatus() to inspect). Thus, you will need to be aware of
- the Paradox Engine's error codes.
-
- ***************************************************************************
- Class Function Documentation
-
- For purposes of clarity, assume that you have declared a class "Client."
- The following functions would be defined:
-
- //------------------- Native (Generated) Functions ------------------------
- //-------------------------------------------------------------------------
- Constructor: Client() [format <ClassName>()]
- Creates an instance of Client. If the client database does not exist, it
- is created. If it is not open, it is automatically opened. The object does
- not reflect any record in the database when first created. All strings and
- lists are empty, all scalar values are set to zero.
-
- //-------------------------------------------------------------------------
- Constructor: Client(Client& val) [the copy constructor]
- Creates a new, identical instance of Client. The client database will be
- created and open since you must have already created a client to pass in!
- The new object reflects all of the values of the passed in object. OELists
- are not copied! The same OEList pointer is now used in both objects. If
- you make a change to the list using the first object, you are also changing
- the list used by the second. Since the list is meant to reflect the database,
- this is exactly as it should be!
-
- //-------------------------------------------------------------------------
- Operator: Client &operator=(Client &) [the assignment operator]
- See the copy constructor. Best used during the declaration of a reference.
-
- //-------------------------------------------------------------------------
- Private function: int Retrieve [note "Private", do not make public!]
- Copies from the database record to the class' variables. Called from all
- of the "Link..." functions (see below).
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int Store() [see PXRecInsert, PXRecUpdate]
- Moves the contents of the object into the database. If the object is already
- linked to a database record (either from a link function or because it was
- copied from another object) then this will UPDATE the database record. Any
- object possessing a non-zero objectID is assumed to be linked to the matching
- db record. If the object is not yet linked to a database record (objectID
- is equal to 0), then calling Store will add it to the database (PXRecInsert).
- Note that this function reflects the documentation for PXRecUpdate and
- PXRecInsert: an attempt to enter a duplicate key is an error, a non-keyed
- table insert will place the record before the current record, etc.
- Return Value: PXSUCCESS or other engine error code.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- //-------------------------------------------------------------------------
- Function: int LinkToKey(int numkeys, int mode) [See also, PXSrchKey]
- When you define a class, you can specify one or more of its variables
- (starting with the first), as keys. A key variable corresponds to key
- fields in the database. To search using key values, you place these values
- in the object's key variables and call this function. For example, if you
- have three key fields and want to search on the first two, you should place
- values for these first two key fields in the corresponding variables and
- call this function with numkeys = 2. Set Mode equal to any mode legal under
- the PXSrchKey documentation (SEARCHFIRST, etc.) according to your search
- requirements. For example:
- ...
- Client.ID = 1000;
- if (Client.LinkToKey(1, SEARCHFIRST) == PXSUCCESS)
- <do great things...>
-
- Note: if the field is not keyed, this function does nothing but return an
- error.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //------------------- Inherited Functions ---------------------------------
- //-------------------------------------------------------------------------
- Function: int LinkToField(char *fieldname, void *value, int mode)
- [See PXSrchFld]
- To search for a specific value in a specific field, pass in the fieldname,
- the value (cast to a void pointer), and the search mode. For example:
-
- client.LinkToField("LNAME", (void *)"Brittingham", SEARCHFIRST)
- client.LinkToField("ID", (void *)&i, SEARCHFIRST)
-
- Note that the value must be a void pointer. If you really want overloaded
- functions, let me know. It takes up more space but might be worth doing.
- Note also that searches using compound keys are on the way...
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int LinkToRecord(int position) [See PXRecGoto]
- Make object reflect contents of the nth record where n = position.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int LinkToID(const long &ID) [See PXSrchFld]
- Explicitly set object to database record with objectID = ID. Should not
- generally be needed. Note, no mode argument since objectIDs are unique.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int LinkToFirst()
- Make object reflect contents of first database record. If database is
- empty, contents are not changed and error code is returned.
-
- Return Value: PXSUCCESS or other engine error code.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- //-------------------------------------------------------------------------
- Function: int LinkToLast()
- Make object reflect contents of last database record. If database is
- empty, contents are not changed and error code is returned.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int LinkToNext()
- Make object reflect contents of next database record. If there is
- no next record, contents are not changed and error code is returned.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: int LinkToPrev()
- Make object reflect contents of previous database record. If there is
- no previous record, contents are not changed and error code is returned.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- Function: void Unlink();
- Removes the objectID from the object. This allows you to copy an object
- and then unlink it from the database record. If you then Store the object
- it will go in under a new objectID (assuming there is no key conflict).
-
- Return Value: None
-
- //-------------------------------------------------------------------------
- virtual int Destroy() [See PXRecDelete]
- Deletes the database record to which this object corresponds. If the
- object has not been linked, it returns PXERR_RECNOTFOUND. Does not delete
- the object or change any of its values. Note that deleting an object does
- not remove it from the database.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- int NRecs(RECORDNUMBER & nrecs) [See PXTblNRecs]
- Returns the numbers of records in the table that the object works with.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- const int GetStatus()
- Returns the status value. Status is set by the most recent Paradox Engine
- function. This function is useful for testing the success of functions
- that don't return a status value (constructors and operators) although it
- can be used after any Object Engine call.
-
- Return Value: PXSUCCESS or other engine error code.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- //-------------------------------------------------------------------------
- TABLEHANDLE GetTblHdl()
- Returns the Paradox Engine table handle. Can be used if you want to bypass
- the library and work directly with the table. Since the Object Engine does
- not provide direct table manipulation (copy, delete, etc.), you may find
- this function useful.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- RECORDHANDLE GetRecHdl()
- Returns the Paradox Engine record handle. Can be used to bypass the library
- and work directly with the record buffer. Should not be needed unless you
- want to work with multi-field secondary indices (which will be available in
- the next release anyhow).
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- const char *GetTblName()
- Returns the name of the table to which this object is attached.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- long GetObjectID()
- Returns the objectID. Should not be needed.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- char GetDeleteFlag()
- char SetDeleteFlag(char flag)
-
- GetDeleteFlag and SetDeleteFlag are used in conjunction with OELists. When
- an OEList is deleted or cleared, it will check the deleteFlag for each of
- the elements that is points to. If the deleteFlag is TRUE, the object will
- be deleted. Otherwise it will not. In both cases, any reference to the
- object is removed from the OEList. Thus, if you create a pointer to an
- object that you get from an OEList, you should set its deleteFlag to FALSE
- if you want to delete the list but keep the pointer.
-
- Return Value: PXSUCCESS or other engine error code.
-
- //-------------------------------------------------------------------------
- int OEPutDate(const int &fieldno, const struct tm &date) and
- int OEGetDate(const int &, struct tm &)
-
- Used in the classes derived from PersistClass to place dates into specific
- record buffer fields. Used to simplify the process of generating code.
- You should never need to use these functions since you will not work directly
- with record buffers.
-
- Return Value: PXSUCCESS or other engine error code.
-
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- ***************************************************************************
- Object List (OEList) Methods - Introduction
-
- You will generally use OELists by declaring a field to be of type '^' in
- the code generator. This will generate all of the code you need to Store
- and Retrieve nested classes. For example, if you have multiple phone
- numbers for a client, you may want to create a nested list of phone number
- objects and store it with a client record. To pursue the example, assume
- that you have declared a class "Client" and a class "Phones." You want to
- associate zero or more phones with a client but don't want to use a unique
- relational field in both tables since a given phone might be used by more
- than one client (a husband and wife, for example).
-
- In this case, you can declare the Client class with an OEList called
- "phones." When working with a client you can add a phone number in the
- following manner:
-
- Client client;
- Phone phone;
-
- client.LinkToField("LNAME", (void *)"Brittingham", SEARCHFIRST);
- phone.Setnumber("555-1212");
- client.Getphone()->Insert((PersistClass *)&phone);
- client.Store();
-
- Note the following important points:
- The phone object Inserted into the list and the link to the client object
- are both immediately Stored. You do NOT need to call Store on an object
- that you place in an OEList (whether or not the list is owned by another
- PersistClass object). This means that changes you make to a class's OEList
- variables cannot be undone simply by not storing the object.
-
- You CAN have arbitrarily nested OELists. For example, the Phone object
- could have a list of people that the phone number serves. This list may
- include the client object defined above. We avoid recursive infinite loops
- by NOT retrieving the data in a list until you take an action (such as
- inserting an object). This also avoids retrieving a all of the data
- associated with a complex object with nested OELists if you just want to see
- a single field. If you want to make sure that all of the data associated
- with an OEList is in memory immediately, you can use the OEList::Init()
- function.
-
- OELists have listIDs (just as objects have objectIDs). When you place
- objects in an OEList, the objectID of the object and the listID of the list
- are associated and stored. If you later call the OEList constructor with a
- listID (and call Init()), the system will search for all objects that were
- ever put on the list and pull them into memory. This is how OELists are
- stored on PersistClasses: the listID is stored in the object's table as a
- LONG. When the object is retrieved, the listID is used to construct a new
- OEList (see generated source code).
-
- The OEList is both a container and an iterator. This is achieved by having
- the "()" (function) operator return the "current" object on the list. The
- "++" operator moves to the next object on the list. The Reset() function
- makes the first object on the list the current object. For example, you can
- do the following:
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- OEList objlist;
- PersistClass* temp;
- Foo* footemp;
-
- objlist.Insert((PersistClass *)fooptr1); //First position
- objlist.Insert((PersistClass *)fooptr3); //Second position
- objlist.Insert((PersistClass *)fooptr4); //Third position
- // objlist() would now return a pointer to fooptr4.
-
- // Move to first position before iterating.
- objlist.Reset();
- while ((temp = objlist++) != NULL)
- {
- ((Foo *)temp).PrintSelf(); <- Some user-declared function
- }
-
- // OR use a for loop...
- for (objlist.Reset(); footemp = (Foo *)objlist(); objlist++)
- {
- // Insert after fooptr object with ID of 1 (id is user-declared)
- if (footemp->Getid() == 1)
- {
- objlist.Insert((PersistClass *)fooptr2);
- break;
- }
- }
-
-
- ***************************************************************************
- OEList Class Function Documentation
-
- //-------------------------------------------------------------------------
- Constructor: OEList()
- Create a new OEList. This object will be a simple shell without ID or
- any objects inside.
-
- //-------------------------------------------------------------------------
- Constructor: OEList(long inID);
- Create a new OEList. This object will be a simple shell but will have the
- given ID. When Init() is called, all objects associated with the given
- listID will be pulled into memory.
-
- //-------------------------------------------------------------------------
- int Init()
- Instantiate the given OEList. If no listID has been assigned, generate a
- new (unique) listID. If a listID exists, pull out all associated objects
- from the database and store them in memory.
-
- Return Value: TRUE or FALSE.
-
- //-------------------------------------------------------------------------
- Destructor: ~OEList();
- Deletes all of the objects pointed to by the OEList EXCEPT those whose
- deleteFlag is FALSE.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- Also, this function WILL CAUSE AN ERROR WINDOW OR MESSAGE to pop up if you
- attempt to delete a list that has multiple pointers to it. That is,
- whenever an object is copied, it will copy any OEList pointers. In order to
- be a good citizen, it will also inform each OEList (via the AddReference
- function, see below) that a new pointer exists. When you want to delete a
- list, you should make sure that you check this pointer count. The RIGHT way
- to delete a list is:
-
- if ((oelist != NULL) && (oelist->DeleteOK() == TRUE)) delete oelist;
-
- The code generator automatically puts this line into the destructors of all
- classes that have OEList elements. In general, you do not need to worry
- about this at all unless you are declaring your own lists and creating
- multiple pointers. If you just use the code generated by Gen2, you are
- guaranteed never to run into any problems.
-
- //-------------------------------------------------------------------------
- void Insert(PersistClass *curelem)
- Inserts a persistant class into an OEList. If you put an element into the
- OEList and want to keep it around even if the list goes away, call the
- object's SetDeleteFlag function with an argument of FALSE. If you delete
- an object pointed to by a list you may crash your program if you work with
- the list later.
-
- //-------------------------------------------------------------------------
- void Remove()
- Removes the current object from the list (you change the "current object"
- by iterating through a list- see above). If the deleteFlag is TRUE, this
- function deletes the object from memory. Does NOT destroy the object's
- corresponding database record. The on-disk representation of the list is
- immediately updated to reflect this removal.
-
- //-------------------------------------------------------------------------
- PersistClass *operator()()
- Returns the current object. Does not increment or otherwise change the
- state of the list.
-
- //-------------------------------------------------------------------------
- PersistClass *operator++()
- Returns the current object and then increments the "current object" pointer.
-
- //-------------------------------------------------------------------------
- void Reset()
- Moves the "current object" pointer to the first element of the list.
-
- //-------------------------------------------------------------------------
- int Count()
- Returns the number of elements in the OEList. Do not use this for iterating
- unless you are SURE that you will not be changing the list in your iteration.
-
- //-------------------------------------------------------------------------
- void Clear()
- Removes all of the elements on the list. See the Remove() function.
-
- //-------------------------------------------------------------------------
- void AddReference()
- If you will be creating your own pointers to a list, this function is used
- to inform the list of your pointer.
-
- Copyright (c) 1992, Brittingham Software Design, Inc.
-
- //-------------------------------------------------------------------------
- char DeleteOK()
- Decrements the reference count and returns it. This is the opposite of
- AddReference. You should not call this function unless you are removing
- your pointer. Also, you should delete the list if this function returns 1.
- (See the documentation for the destructor).
-
- //-------------------------------------------------------------------------
- const int GetStatus()
- Returns the status of the list. Can be any of: NOTINIT, READY, or FAIL.
-
- //-------------------------------------------------------------------------
- const long GetListID()
- Returns the listID. This number is used in a <listID, objectID, TableName>
- table to keep track of the associations between lists and objects.
-